﻿using System;
using System.Collections.Generic;
using System.Text;

namespace System
{
	public interface ISingleton
	{
		void Initialize();
	}

	public abstract class Singleton : ISingleton
	{
		internal static Dictionary<object, object> instances;

		public object Key { get; internal set; }

		virtual protected void Initialize()
		{
		}

		static internal object CreateInstance(Type type, object key)
		{
			if (instances == null)
			{
				lock (typeof(Singleton))
				{
					if (instances == null)
					{
						instances = new Dictionary<object, object>();
					}
				}
			}

			if (!instances.ContainsKey(key))
			{
				lock (typeof(Singleton))
				{
					if (!instances.ContainsKey(key))
					{
						Singleton instance = type.InvokeMember(null, System.Reflection.BindingFlags.CreateInstance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, null, null) as Singleton;
						instance.Key = key;

						instance.Initialize();

						instances.Add(key, instance);
					}
				}
			}

			return instances[key];
		}

		#region ISingleton Members

		void ISingleton.Initialize()
		{
			this.Initialize();
		}

		#endregion
	}

	public abstract class Singleton<T> : Singleton
		where T : Singleton
	{
		static public T Instance
		{
			get { return CreateInstance(); }
		}

		static public T CreateInstance()
		{
			return CreateInstance(typeof(T).FullName);
		}

		static public T CreateInstance(object key)
		{
			return (T)Singleton.CreateInstance(typeof(T), key);
		}
	}
}
